/*
 * @Author: 李琪 liqi@lark2game.com
 * @Date: 2025-08-27 11:52:57
 * @LastEditors: 李琪 liqi@lark2game.com
 * @LastEditTime: 2025-08-27 14:11:31
 * @FilePath: /gameWorld/assets/script/porline/PerlinNoise.ts
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
export class PerlinNoise {
    private permutation: number[];
    private p: number[];

    constructor(seed: number = Math.random() * 256) {
        this.permutation = new Array(256);
        this.p = new Array(512);

        // 初始化排列数组
        for (let i = 0; i < 256; i++) {
            this.permutation[i] = i;
        }

        // 根据种子随机打乱排列
        let rng = this.mulberry32(seed);
        for (let i = 255; i > 0; i--) {
            const j = Math.floor(rng() * (i + 1));
            [this.permutation[i], this.permutation[j]] = [this.permutation[j], this.permutation[i]];
        }

        // 复制到p数组以便快速查找
        for (let i = 0; i < 256; i++) {
            this.p[i] = this.p[i + 256] = this.permutation[i];
        }
    }

    // 简单的伪随机数生成器
    private mulberry32(seed: number): () => number {
        return function () {
            seed |= 0;
            seed = seed + 0x6D2B79F5 | 0;
            let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
            t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
            return ((t ^ t >>> 14) >>> 0) / 4294967296;
        };
    }

    //  fade函数用于平滑插值
    private fade(t: number): number {
        return t * t * t * (t * (t * 6 - 15) + 10);
    }

    // 线性插值
    private lerp(t: number, a: number, b: number): number {
        return a + t * (b - a);
    }

    // 梯度函数
    private grad(hash: number, x: number, y: number): number {
        const h = hash & 15;
        const u = h < 8 ? x : y;
        const v = h < 4 ? y : h === 12 || h === 14 ? x : 0;
        return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
    }

    // 2D柏林噪声
    public noise(x: number, y: number): number {
        const X = Math.floor(x) & 255;
        const Y = Math.floor(y) & 255;

        x -= Math.floor(x);
        y -= Math.floor(y);

        const u = this.fade(x);
        const v = this.fade(y);

        const A = this.p[X] + Y;
        const B = this.p[X + 1] + Y;

        return this.lerp(v,
            this.lerp(u,
                this.grad(this.p[A], x, y),
                this.grad(this.p[B], x - 1, y)
            ),
            this.lerp(u,
                this.grad(this.p[A + 1], x, y - 1),
                this.grad(this.p[B + 1], x - 1, y - 1)
            )
        );
    }

    // 生成分形噪声（多个倍频叠加）
    public fractalNoise(x: number, y: number, octaves: number = 4, persistence: number = 0.5): number {
        let total = 0;
        let frequency = 1;
        let amplitude = 1;
        let maxValue = 0;

        for (let i = 0; i < octaves; i++) {
            total += this.noise(x * frequency, y * frequency) * amplitude;
            maxValue += amplitude;
            amplitude *= persistence;
            frequency *= 2;
        }

        return total / maxValue;
    }
}